﻿/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "ObjectManager.h"
#include "Shared/Util.h"
#include "World/World.h"


ObjectManager::ObjectManager(void)
    : PlayerXPperLevel_()
    , Name2Guid_()
    , CharGuids_()
{

}

ObjectManager::~ObjectManager(void)
{

}

const struct CreatureInfo* ObjectManager::GetCreatureInfo(std::uint32_t _ID)
{ return sSQLStorages.CreatureStorage_.LookupEntry<struct CreatureInfo>(_ID); }
const struct ItemPrototype* ObjectManager::GetItemPrototype(std::uint32_t _ID)
{ return sSQLStorages.ItemStorage_.LookupEntry<struct ItemPrototype>(_ID); }
const struct PlayerInfo* ObjectManager::GetPlayerInfo(std::uint32_t _Race, std::uint32_t _Class)
{
    if (_Race >= MAX_RACES)   { return NULL; }
    if (_Class >= MAX_CLASSES) { return NULL; }
    PlayerInfo const* _Info = &PlayerInfo_[_Race][_Class];
    if (_Info->DisplayId_M == 0 || _Info->DisplayId_F == 0) { return NULL; }
    return _Info;
}

bool ObjectManager::NormalizePlayerName(std::string& _Name)
{
    if (_Name.empty()) {
        return false;
    }

    wchar_t _WStrBuf[MAX_INTERNAL_PLAYER_NAME + 1];
    size_t _WStrLen = MAX_INTERNAL_PLAYER_NAME;

    if (!Utf8toWStr(_Name, &_WStrBuf[0], _WStrLen)) {
        return false;
    }

    _WStrBuf[0] = wcharToUpper(_WStrBuf[0]);
    for (size_t _I = 1; _I < _WStrLen; ++_I) {
        _WStrBuf[_I] = wcharToLower(_WStrBuf[_I]);
    }

    if (!WStrToUtf8(_WStrBuf, _WStrLen, _Name)) {
        return false;
    }

    return true;
}

enum LanguageType
{
    LT_BASIC_LATIN = 0x0000,
    LT_EXTENDEN_LATIN = 0x0001,
    LT_CYRILLIC = 0x0002,
    LT_EAST_ASIA = 0x0004,
    LT_ANY = 0xFFFF
};
static LanguageType GetRealmLanguageType(bool create)
{
    switch (sWorld.GetConfig(CONFIG_UINT32_REALM_ZONE))
    {
    case REALM_ZONE_UNKNOWN:                            // any language
    case REALM_ZONE_DEVELOPMENT:
    case REALM_ZONE_TEST_SERVER:
    case REALM_ZONE_QA_SERVER:
        return LT_ANY;
    case REALM_ZONE_UNITED_STATES:                      // extended-Latin
    case REALM_ZONE_OCEANIC:
    case REALM_ZONE_LATIN_AMERICA:
    case REALM_ZONE_ENGLISH:
    case REALM_ZONE_GERMAN:
    case REALM_ZONE_FRENCH:
    case REALM_ZONE_SPANISH:
        return LT_EXTENDEN_LATIN;
    case REALM_ZONE_KOREA:                              // East-Asian
    case REALM_ZONE_TAIWAN:
    case REALM_ZONE_CHINA:
        return LT_EAST_ASIA;
    case REALM_ZONE_RUSSIAN:                            // Cyrillic
        return LT_CYRILLIC;
    default:
        return create ? LT_BASIC_LATIN : LT_ANY;        // basic-Latin at create, any at login
    }
}
bool isValidString(std::wstring _Wstr, std::uint32_t _StrictMask, bool _NumericOrSpace, bool _Create = false)
{
    if (_StrictMask == 0)                                    // any language, ignore realm
    {
        if (isExtendedLatinString(_Wstr, _NumericOrSpace)) {
            return true;
        }
        if (isCyrillicString(_Wstr, _NumericOrSpace)) {
            return true;
        }
        if (isEastAsianString(_Wstr, _NumericOrSpace)) {
            return true;
        }
        return false;
    }

    if (_StrictMask & 0x2)                                   // realm zone specific
    {
        LanguageType _LangType = GetRealmLanguageType(_Create);
        if (_LangType & LT_EXTENDEN_LATIN) {
            if (isExtendedLatinString(_Wstr, _NumericOrSpace)) {
                return true;
            }
        }
        
        if (_LangType & LT_CYRILLIC) {
            if (isCyrillicString(_Wstr, _NumericOrSpace)) {
                return true;
            }
        }
        
        if (_LangType & LT_EAST_ASIA) {
            if (isEastAsianString(_Wstr, _NumericOrSpace)) {
                return true;
            }
        }
        
    }

    if (_StrictMask & 0x1)                                   // basic Latin
    {
        if (isBasicLatinString(_Wstr, _NumericOrSpace)) {
            return true;
        }
    }

    return false;
}
std::uint8_t ObjectManager::CheckPlayerName(const std::string& _Name, bool _Create)
{
    std::wstring _Wname;
    if (!Utf8toWStr(_Name, _Wname)) {
        return CHAR_NAME_INVALID_CHARACTER;
    }

    if (_Wname.size() > MAX_PLAYER_NAME) {
        return CHAR_NAME_TOO_LONG;
    }

    std::uint32_t _MinName = sWorld.GetConfig(CONFIG_UINT32_MIN_PLAYER_NAME);
    if (_Wname.size() < _MinName) {
        return CHAR_NAME_TOO_SHORT;
    }

    std::uint32_t _StrictMask = sWorld.GetConfig(CONFIG_UINT32_STRICT_PLAYER_NAMES);
    if (!isValidString(_Wname, _StrictMask, false, _Create)) {
        return CHAR_NAME_MIXED_LANGUAGES;
    }

    return CHAR_NAME_SUCCESS;
}
bool ObjectManager::IsReservedName(const std::string& _Name)
{
    return false;
}
ObjectGuid ObjectManager::GetPlayerGuidByName(const std::string& _Name)
{
    Name2Guid::const_iterator _Iter = Name2Guid_.find(_Name);
    if (_Iter != Name2Guid_.end()) {
        return ObjectGuid(HIGHGUID_PLAYER, _Iter->second);
    }
    return ObjectGuid();
}
void ObjectManager::AddPlayerGuidByName(const std::string& _Name, std::uint32_t _GuidLow)
{
    Name2Guid_[_Name] = _GuidLow;
}